package com.cc.visitor.utils;

import com.cc.alltype.BeanUtils;
import com.cc.alltype.BusinessException;
import com.cc.alltype.DatetimeUtils;
import com.cc.visitor.dao.LogMiniMapper;
import com.cc.visitor.dao.UserWeixinMapper;
import com.cc.visitor.dao.VisitMapper;
import com.cc.visitor.entity.LogMini;
import com.cc.visitor.entity.UserWeixin;
import com.cc.visitor.entity.Visit;
import com.cc.visitor.entity.wechat.WxAccessToken;
import com.cc.visitor.entity.wechat.templateMessage.*;
import com.cc.visitor.service.TemplateMsgService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.thoughtworks.xstream.XStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @author chanchaw
 * @create 2024-12-02 14:17
 */
@Service
public class TemplateMsgUtils {
    @Autowired
    private VisitMapper visitMapper;
    @Autowired
    private UserWeixinMapper userWeixinMapper;
    private static final Logger logger = LoggerFactory.getLogger("wxmp");
    @Autowired
    private TemplateMsgService templateMsgService;
    private ObjectMapper mapper = new ObjectMapper();
    @Autowired
    private WxAccessToken wxAccessToken;
    @Autowired
    private RestTemplateUtils restTemplateUtils;
    @Autowired
    private LogMiniMapper logMiniMapper;

    /**
     * 访客到达门卫扫描快捷通道的二维码查询后访单没有审核
     * 发送模板消息提醒受访者审核通过
     * @param visitId 访单主键 = visit.id
     * @return
     * @throws Exception
     */
    public void pushArrived(Integer visitId) {
        visitId = Optional.ofNullable(visitId).orElse(0);
        Visit visit = visitMapper.selectOneById(visitId);
        if(visit == null) return;

        List<Object> itemDataList = new ArrayList<>();
        String realName = Optional.ofNullable(visit.getVisitorRealName()).orElse("");
        String company = Optional.ofNullable(visit.getVisitorCompany()).orElse("");
        String phone = Optional.ofNullable(visit.getVisitorPhone()).orElse("");
        itemDataList.add(realName);
        itemDataList.add(company);
        itemDataList.add(phone);
        String nowString = DatetimeUtils.formatNow();
        itemDataList.add(nowString);// 当前时间作为访客扫码的时间
        itemDataList.add("访客已到门卫，请尽快审核访单！");
        String intervieweeOpenId = Optional.ofNullable(visit.getIntervieweeOpenId()).orElse("");
        if(intervieweeOpenId.length() == 0) return;
        try {
            push8Name(SysConst.TEMPLATE_NAME_VISITOR_ARRIVED,intervieweeOpenId,"","pages/billqr/billqr?id=" + visitId,itemDataList);
        } catch (Exception e) {
            logger.info("推送受访者访客已到门卫提醒审核时出现异常，访单主键：" + visitId);
        }
    }

    /**
     * 推送模板消息给开发人员
     * @param msgList 必须是长度5为的字符串集合，使用模板：TnzMavqm0Is6r-sK7NAjCY0GeVwQ344n9kdE-Dt4vOs
     */
    public String pushDevAlert(List<Object> msgList) throws Exception {
        List<UserWeixin> devs = userWeixinMapper.getDevs();
        if(devs == null || devs.size() == 0) return "user_weixin中没有开发人员，无法推送";
        if(msgList == null || msgList.size() != 5) throw new BusinessException("推送给开发人员的报警消息要求消息长度为5！");

        String ret = "";
        for (UserWeixin dev : devs) {
            String openId = Optional.ofNullable(dev.getOpenId()).orElse("");
            String realName = Optional.ofNullable(dev.getRealName()).orElse("");
            if(openId.length() > 0){
                push8Name(SysConst.TEMPLATE_NAME_DEV_ALERT,openId,"","", msgList);
                ret = ret + realName + ",";
            }
        }
        return ret;
    }

    /**
     * 测试用，可删除
     * @throws Exception
     */
    public void pushMap() throws Exception {
        List<Object> strings = new ArrayList<>();
        strings.add("请点击我进行注册");
        strings.add("10");
        strings.add(DatetimeUtils.formatNow());
        Map<String, Object> templateMsgMap = templateMsgService.getTemplateMsgMap("引导新用户注册",
                "odDItvwJVRN7XNuTLTqGSfTVrs-Y", "", "pages/register/register", strings);
        String szToken = wxAccessToken.getAccessToken();
        String reqUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + szToken;
        String jsonString = mapper.writeValueAsString(templateMsgMap);
        String ret = HttpUtils.postJson( reqUrl, jsonString);
        System.out.println("推送模板消息得到的响应：" + ret);
    }

    /**
     * 按照模板名称 templateName 构建消息体对象并推送给指定微信用户
     * @param templateName 模板名称 = template_msg_main.sname
     * @param openId 微信用户 openId
     * @param url 点击模板消息后跳转的 url
     * @param miniProgramPath 点击模板消息后跳转的微信小程序页面，一般为：pages/register/register
     * @param itemDataList 模板消息要素构成的集合
     * @throws Exception
     */
    public void push8Name(String templateName, String openId, String url, String miniProgramPath, List<Object> itemDataList) throws Exception {
        openId = Optional.ofNullable(openId).orElse("");
        if(openId.length() == 0){
            logger.info("推送名称为" + templateName + "的模板消息时openId为空，无法推送模板消息！");
            return;
        }

        Map<String, Object> templateMsgMap = templateMsgService.getTemplateMsgMap(templateName, openId, url, miniProgramPath, itemDataList);
        String szToken = wxAccessToken.getAccessToken();
        String reqUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + szToken;
        String jsonString = mapper.writeValueAsString(templateMsgMap);
        String ret = HttpUtils.postJson( reqUrl, jsonString);
        System.out.println("推送模板消息得到的响应：" + ret);
    }

    /**
     * 推送给用户用户注册的模板消息
     * @param openId 接收消息的微信用户 openId
     * @param userType 微信用户类型，10普通访客，11贵宾访客
     */
    public void pushRegister(String openId, Integer userType){
        openId = Optional.ofNullable(openId).orElse("");
        if(openId.length() == 0){
            logger.info("推送给新用户提醒注册时目标openId为空，无法推送模板消息！");
            return;
        }
        List<Object> itemDataList = new ArrayList<>();
        itemDataList.add("点击我进行注册");
        itemDataList.add(userType);
        itemDataList.add(DatetimeUtils.formatNow());
        String miniPath = getMiniRegisterPath(userType, openId);
        try {
            push8Name(SysConst.TEMPLATE_NAME_REGISTER,openId,"",miniPath,itemDataList);
        } catch (Exception e) {
            logger.info("推送注册用模板消息时出现异常，openId:{}",openId);
        }
    }

    /**
     * 根据用户类型，返回跳转到小程序的页面：访客注册、受访用户注册
     * 2024年12月12日 初次制作只支持两种用户：访客、受访用户
     * @param userType
     * @return
     */
    private String getMiniRegisterPath(Integer userType, String openId){
        String url = "";
        if(userType < 20) url = SysConst.MINI_PATH_REGISTER;// 访客注册
        else url = SysConst.MINI_PATH_REGISTER_INTERVIEWEE;// 受访用户注册
        url = url + "?userType=" + userType + "&openId=" + openId + "&subscribeTime=" + DatetimeUtils.formatNow();
        // 推送注册用模板消息中携带的miniPath
        LogMini logMini = LogMini.builder().page("java后台推送注册用模板消息").func("TemplateMsgUtils#getMiniRegisterPath").category("java")
                .remark("推送注册用模板消息中携带的miniPath:" + url).build();
        logMiniMapper.insertSelective(logMini);
        return url;
    }

    /**
     * 受访者驳回访单后系统发送给访客模板消息，通知其访单已被驳回
     * @param visitorOpenId
     * @param rejectRemark
     */
    public void pushVisitorReject(String visitorOpenId, String visitDesc,String rejectRemark){
        visitorOpenId = Optional.ofNullable(visitorOpenId).orElse("");
        if(visitorOpenId.length() == 0){
            logger.info("推送为访客提醒访单已被驳回时访客的openId为空，无法推送模板消息！");
            return;
        }

        List<Object> itemDataList = new ArrayList<>();
        // 获取当前日期时间
        String nowString = DatetimeUtils.formatNow();
//        String substring = nowString.substring(5, 11);
        itemDataList.add(nowString);// 推送模板消息的时间
        itemDataList.add(visitDesc);// 预约日
        itemDataList.add(rejectRemark);// 驳回原因
        try {
            push8Name(SysConst.TEMPLATE_NAME_REJECT_VISITOR,visitorOpenId,"","",itemDataList);
        } catch (Exception e) {
            logger.info("推送访客访单被驳回时出现异常，访客openId:{}",visitorOpenId);
        }
    }

    public void pushInterviewee2Audit(Integer visitId){
        Visit visit = visitMapper.selectOneById(visitId);
        if(visit == null) return;
        pushInterviewee2Audit(visit);
    }

    /**
     * 访客新增一个访单后推送给受访者提醒其审核的模板消息
     * @param record
     */
    public void pushInterviewee2Audit(Visit record){
        if(record == null) {
            logger.info("推送给受访者提醒审核消息时传入了空对象，无法推送模板消息！");
            return;
        }

        String  intervieweeOpenId = Optional.ofNullable(record.getIntervieweeOpenId()).orElse("");
        Integer id = Optional.ofNullable(record.getId()).orElse(0);
        if(intervieweeOpenId.length() == 0){
            logger.info("推送给受访者提醒审核消息时主键" + id + "中的受访者openId为空，无法推送模板消息！");
            return;
        }

        List<Object> itemDataList = new ArrayList<>();
        String visitorCompany = Optional.ofNullable(record.getVisitorCompany()).orElse("");
        itemDataList.add(visitorCompany);

        String visitorRealName = Optional.ofNullable(record.getVisitorRealName()).orElse("");
        itemDataList.add(visitorRealName);

        String visitorPhone = Optional.ofNullable(record.getVisitorPhone()).orElse("");
        itemDataList.add(visitorPhone);

        LocalDateTime startTime = Optional.ofNullable(record.getStartTime()).orElse(LocalDateTime.now());
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MM-dd HH:mm");
        String formatTime = startTime.format(dateTimeFormatter);
        itemDataList.add(formatTime);

        Integer numberOfPeople = Optional.ofNullable(record.getNumberOfPeople()).orElse(1);
        itemDataList.add(numberOfPeople);

        try {
            // 推送受访者提醒审核的模板消息，点击后跳转到所有访单列表
            // push8Name(SysConst.TEMPLATE_NAME_AUDIT_BILL,intervieweeOpenId,"","pages/mill/mill",itemDataList);
            // 2025年3月2日 修改模板消息关联的小程序页面，点击后跳转到当前访单的详情页，此页面显示了访单的所有信息
            push8Name(SysConst.TEMPLATE_NAME_AUDIT_BILL,intervieweeOpenId,"","pages/billqr/billqr?id=" + id, itemDataList);
        } catch (Exception e) {
            logger.info("推送受访者新访单时出现异常，访单主键:{}",record.getId());
        }
    }

    public void pushVisitorAudited(Integer visitId){
        Visit visit = visitMapper.selectOneById(visitId);
        if(visit == null) return;
        pushVisitorAudited(visit);
    }

    // 受访者审核通过后通知访客已审核通过
    public void pushVisitorAudited(Visit record){
        if(record == null) return;
        String visitorOpenId = Optional.ofNullable(record.getVisitorOpenId()).orElse("");
        if(visitorOpenId.length() == 0) return;
        String realName = Optional.ofNullable(record.getIntervieweeRealName()).orElse("");
        LocalDateTime startTime = record.getStartTime();
        String startTimeString = startTime.format(DateTimeFormatter.ofPattern("MM-dd HH:mm"));
        List<Object> itemDataList = new ArrayList<>();
        itemDataList.add("常熟翔轮精工有限公司");
        itemDataList.add(realName);
        itemDataList.add(startTimeString);
        itemDataList.add("受访人已审核通过");
        String miniPath = "pages/recordv/recordv?id=" + record.getId() + "&isOpenBill=true";
        try {
            push8Name(SysConst.TEMPLATE_NAME_PUSH_VISITOR_AUDITED,visitorOpenId,"",miniPath,itemDataList);
        } catch (Exception e) {
            logger.info("推送访客通知已审核通过时出现异常，访单主键:{}",record.getId());
        }
    }
    public void pushIntervieweeEntry(Integer visitId){
        Visit visit = visitMapper.selectOneById(visitId);
        if(visit == null) return;
        pushIntervieweeEntry(visit);
    }
    // 访客扫码进场后通知受访者模板消息
    public void pushIntervieweeEntry(Visit record){
        String visitorRealName = Optional.ofNullable(record.getVisitorRealName()).orElse(" ");
        String visitorPhone = Optional.ofNullable(record.getVisitorPhone()).orElse(" ");
        LocalDateTime admissionTime = Optional.ofNullable(record.getAdmissionTime()).orElse(LocalDateTime.now());
        String admissionTimeString = admissionTime.format(DateTimeFormatter.ofPattern("MM-dd HH:mm:ss"));
        String intervieweeRealName = Optional.ofNullable(record.getIntervieweeRealName()).orElse("");
        String intervieweeOpenId = Optional.ofNullable(record.getIntervieweeOpenId()).orElse("");

        List<Object> itemDataList = new ArrayList<>();
        itemDataList.add(visitorRealName);
        itemDataList.add(visitorPhone);
        itemDataList.add(admissionTimeString);
        itemDataList.add(intervieweeRealName);
        try {
            push8Name(SysConst.TEMPLATE_NAME_PUSH_INTERVIEWEE_ENTRY,intervieweeOpenId,"","",itemDataList);
        } catch (Exception e) {
            logger.info("推送受访者访客已进场时出现异常，访单主键:{}",record.getId());
        }
    }
    public void pushIntervieweeLeave(Integer visitId){
        Visit visit = visitMapper.selectOneById(visitId);
        if(visit == null) return;
        pushIntervieweeLeave(visit);
    }
    // 访客离场后通知受访者
    public void pushIntervieweeLeave(Visit record){
        String visitorRealName = Optional.ofNullable(record.getVisitorRealName()).orElse(" ");
        String visitorPhone = Optional.ofNullable(record.getVisitorPhone()).orElse(" ");
        String leaveTimeString = LocalDateTime.now().format(DateTimeFormatter.ofPattern("MM-dd HH:mm:ss"));
        String intervieweeOpenId = Optional.ofNullable(record.getIntervieweeOpenId()).orElse("");

        List<Object> itemDataList = new ArrayList<>();
        itemDataList.add(visitorRealName);
        itemDataList.add(visitorPhone);
        itemDataList.add(leaveTimeString);
        try {
            push8Name(SysConst.TEMPLATE_NAME_PUSH_INTERVIEWEE_OUT,intervieweeOpenId,"","",itemDataList);
        } catch (Exception e) {
            logger.info("推送受访者访客已离场时出现异常，访单主键:{}",record.getId());
        }
    }

    // 查询已经审核的前一天的访单，没有扫码进场的访单，通知受访者
    public int pushIntervieweeAuditedUnUse(){
        List<Visit> list = visitMapper.getAuditedUnUse();
        if(list == null || list.size() == 0) return 0;

        for (Visit item : list) {
            String openId = Optional.ofNullable(item.getIntervieweeOpenId()).orElse("");
            if(openId.length() == 0) continue;

            Integer id = Optional.ofNullable(item.getId()).orElse(0);
            String visitorName = Optional.ofNullable(item.getVisitorRealName()).orElse("");
            String visitorCompany = Optional.ofNullable(item.getVisitorCompany()).orElse("");
            String endTime = DatetimeUtils.formatDate(item.getEndTime(), null);
            String remark = "已审核，未进场";

            List<Object> itemDataList = new ArrayList<>();
            itemDataList.add(visitorName);
            itemDataList.add(visitorCompany);
            itemDataList.add(endTime);
            itemDataList.add(remark);
            try {
                // 模板消息携带小程序地址，点击后打开对应的访单，可继续操作给驳回
                push8Name(SysConst.TEMPLATE_NAME_AUDITED_OVERDUE,openId,"","pages/billqr/billqr?id=" + id,itemDataList);
            } catch (Exception e) {
                logger.info("推送受访者已审核未进场的访单主键{}出现异常",id);
            }
        }
        return list.size();
    }
}
